package net.qiqb.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class QiqbComponentScannerConfigurer implements BeanDefinitionRegistryPostProcessor, SmartInitializingSingleton {

    private String basePackage;

    private static Map<BeanDefinitionRegistry, SpringExecutionContext> contextMap = new ConcurrentHashMap<>();


    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        ClassPathComponentScanner scanner = new ClassPathComponentScanner(registry);
        scanner.registerFilters();

        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
        // 扫描 module service
        //ModuleServiceComponentScanner serviceComponentScanner = new ModuleServiceComponentScanner(registry);
        // serviceComponentScanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));

        if (contextMap.putIfAbsent(registry, new SpringExecutionContext()) == null) {
            final SpringExecutionContext springExecutionContext = contextMap.get(registry);
            ConfigurableListableBeanFactory beanFactory = findBeanFactory(registry);
            beanFactory.registerSingleton(SpringExecutionContext.class.getName(), springExecutionContext);
        }
        // 将module api 注册到spring 容器里

        final SpringExecutionContext springExecutionContext = contextMap.get(registry);
        springExecutionContext.addAllAggregateRootBeanDefinition(scanner.getAggregateRootBeanDefinition());
        springExecutionContext.addAllAttachAggregateBeanDefinition(scanner.getAttachAggregateBeanDefinition());
        springExecutionContext.addAllCommandBeanDefinition(scanner.getCommandBeanDefinition());


    }

    private static ConfigurableListableBeanFactory findBeanFactory(BeanDefinitionRegistry registry) {
        ConfigurableListableBeanFactory beanFactory;
        if (registry instanceof ConfigurableListableBeanFactory) {
            beanFactory = (ConfigurableListableBeanFactory) registry;
        } else if (registry instanceof GenericApplicationContext genericApplicationContext) {
            beanFactory = genericApplicationContext.getBeanFactory();
        } else {
            throw new IllegalStateException("Can not find Spring BeanFactory from registry: " + registry.getClass().getName());
        }
        return beanFactory;
    }


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }


    public void setBasePackage(String basePackage) {
        this.basePackage = basePackage;
    }

    @Override
    public void afterSingletonsInstantiated() {

    }
}
